home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / ivd2dvi / io.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  12KB  |  521 lines

  1. /*
  2.  *  Input/output routines for ivd2dvi.  Copyright 1988 by Larry Denenberg.
  3.  *  May be freely distributed as long as this notice is retained.
  4.  *  
  5.  *  Here are the naming conventions for input routines: A routine is named
  6.  *  "Read..." if it merely reads something from standard input, e.g.
  7.  *  /ReadByte/, /ReadSigned/.  Recall that the input DVI file always
  8.  *  comes via standard input.  As in C, there are routines "FRead..."
  9.  *  whose first argument is of type FILE*; these read from an arbitrary
  10.  *  file and are used to read TFM files.  We also have the "Copy..."
  11.  *  routines; these are just like their "Read..." counterparts but also
  12.  *  copy every byte read to the output DVI file.  There are no "FCopy..."
  13.  *  routines for obvious reasons.  The routine /CopyNBytes/ has no "Read"
  14.  *  analogue because it returns no value.
  15.  */
  16.  
  17.  
  18. #include <stdio.h>
  19. #include "global.h"
  20. #include "commands.h"
  21.  
  22. /* Procedure and global variable defined in auxiliary.c */
  23. extern void BadDVIAbort();
  24. extern font *CurFont;
  25.  
  26. /* Global variables defined in ivd2dvi.c */
  27. extern int State;
  28. extern char *ProgramName;
  29.  
  30. /* Global variables defined here */
  31. unsigned BufSize = BUFDEFAULTSIZE;    /* buffer size, mutable with -b    */
  32. unsigned_byte *Buffer;        /* first char of input buffer        */
  33. unsigned_byte *BufEnd;        /* pointer just beyond buffer area    */
  34. unsigned_byte *BufFirstNonchar;    /* first unused spot; save input here    */
  35. unsigned_byte *BufPointer;    /* pointer into buffer; read from here    */
  36. boolean ReadingCommand = FALSE;    /* true iff reading a DVI main command     */
  37. unsigned_byte *VStack;        /* start of nesting validation stack    */
  38. unsigned_byte *VEnd;        /* pointer just beyond vstack area    */
  39. unsigned_byte *VPointer;    /* vstack pointer to first unused slot    */
  40. long BytesOutput = 0L;        /* number of bytes written to output    */
  41.  
  42.  
  43. /* Procedures defined in this file, in order of definition */
  44. void InitIOBuffers();
  45. unsigned_byte ReadByte();
  46. void NestingValidate(), BufOverflow();
  47. unsigned_byte ReadCommand(), CopyByte(), FReadByte();
  48. void SkipNBytes(), FSkipNBytes(), CopyNBytes();
  49. long ReadUnsigned(), FReadUnsigned(), ReadSigned(), FReadSigned();
  50. long CopyWord(), CopyUnsigned();
  51. unsigned_byte *ReadFilePosition();
  52. void ResetFilePosition(), RereadLastByte();
  53. void WriteByte(), WriteWord(), WriteNumber(), WriteString();
  54. unsigned SignedBytes();
  55.  
  56.  
  57.  
  58. /*
  59.  *  Initialize two of the three main memory areas in ivd2dvi.  The
  60.  *  size of each is a function of the value /BufSize/ which can be
  61.  *  changed by the user with the -b flag.  So the user doesn't need to
  62.  *  know that there are lots of buffers with different sizes;  if there's
  63.  *  not enough room, using the -b flag will make them all bigger.
  64.  */
  65. void
  66. InitIOBuffers()
  67. {
  68.   Buffer = SEQALLOC(BufSize, unsigned_byte);
  69.   BufPointer = NULL;
  70.   BufFirstNonchar = Buffer;
  71.   BufEnd = Buffer + BufSize;
  72.  
  73.   VStack = SEQALLOC(BufSize/SMALLBUFDIVISOR, unsigned_byte);
  74.   VPointer = VStack;
  75.   VEnd = VStack + BufSize/SMALLBUFDIVISOR;
  76.  
  77.   if ((Buffer == NULL) || (VStack = NULL)) {
  78.     fprintf(stderr, "\n%s fatal error: can't allocate buffers\n",
  79.             ProgramName);
  80.     exit(3);
  81.   }
  82. }
  83.  
  84.  
  85.  
  86.  
  87. /*
  88.  *  Read a byte from the input DVI file.  All input routines that read
  89.  *  standard input must come through here.
  90.  *
  91.  *  The problem to worry about is that ivd2dvi frequently needs to reread
  92.  *  input.  Rather than doing seeks, we've (perhaps foolishly) decided to
  93.  *  buffer input so we can see it again later.  This means that ivd2dvi is
  94.  *  a true filter, which is a useless advantage since TeX doesn't write
  95.  *  its standard output and since most dvi drivers (dvi2ps in particular)
  96.  *  need real files and can't read standard input.
  97.  *
  98.  *  Now, we don't buffer *all* input, since we know that only if we're
  99.  *  simulating will we need to reread the input.  So anytime we're
  100.  *  reading from the real input file and we're simulating, we save the
  101.  *  character in the buffer.
  102.  *
  103.  *  /BufPointer/ is the place in the buffer from which we're reading
  104.  *  saved input.  It also serves as a flag; if it's NULL, then we're not
  105.  *  reading saved input at all.  So the basic idea is:  if /BufPointer/
  106.  *  is pointing, return the character it points to and advance it.
  107.  *  Otherwise, do a real read, and save if simulating.
  108.  *
  109.  *  What if /BufPointer/ points, but there's no more input?  Then we want
  110.  *  to go back to reading real input: set /BufPointer/ to NULL and call
  111.  *  ourselves recursively to force real input.  We also take this
  112.  *  opportunity to clear out the buffer and start over, a step which is
  113.  *  justified only because we start rereading input only when we stop
  114.  *  simulating (thus nobody can need the saved input anymore).
  115.  *
  116.  *  Note that it's an error if standard input ever comes to EOF; we
  117.  *  should have seen the postamble and quit.  Finally, /ReadingCommand/
  118.  *  is TRUE iff the byte is a command and not a parameter; in this case
  119.  *  we check it with /NestingValidate/.
  120.  */
  121. unsigned_byte
  122. ReadByte()
  123. {
  124.   int nextchar;
  125.  
  126.   if (BufPointer) {
  127.     if (BufPointer < BufFirstNonchar) return *BufPointer++;
  128.     else {
  129.       BufPointer = NULL;
  130.       BufFirstNonchar = Buffer;
  131.       return ReadByte();
  132.     }
  133.   } else {
  134.     nextchar = getchar();
  135.     if (nextchar == EOF) BadDVIAbort("unexpected EOF");
  136.     if (ReadingCommand) NestingValidate((unsigned_byte) nextchar);
  137.     if (State >= SIMULATING) {
  138.       *BufFirstNonchar++ = (unsigned_byte) nextchar;
  139.       if (BufFirstNonchar > BufEnd) BufOverflow();
  140.     }
  141.     return nextchar;
  142.   }
  143. }
  144.  
  145.  
  146.  
  147. /*
  148.  *  Test a character for nesting.  Since dvitype doesn't check DVI-IVD
  149.  *  files for validity, it's important to do careful checking here---
  150.  *  ivd2dvi will get horribly confused if reflections and pushes don't
  151.  *  nest properly.  This routine gets called to validate every single
  152.  *  command read from the input file.  The method is simple: if the
  153.  *  command is PUSH, BEG_REFLECT, or BOP, just push it on the stack (the
  154.  *  stack is the tiny /VStack/, not used for anything else).  If the
  155.  *  command is POP, END_REFLECT, or EOP, pop a command from the stack and
  156.  *  be sure it matches.  Ignore all other commands.
  157.  */
  158. void
  159. NestingValidate(nextchar)
  160. unsigned_byte nextchar;
  161. {
  162.   switch (nextchar) {
  163.     case PUSH: case BEG_REFLECT: case BOP:
  164.       if (VPointer >= VEnd) BufOverflow(); else *VPointer++ = nextchar;
  165.       break;
  166.     case POP:
  167.       if ((VPointer <= VStack) || (*--VPointer != PUSH))
  168.     BadDVIAbort("reflection commands incorrectly nested");
  169.       break;
  170.     case EOP:
  171.       if ((VPointer <= VStack) || (*--VPointer != BOP))
  172.     BadDVIAbort("reflection commands incorrectly nested");
  173.       break;
  174.     case END_REFLECT:
  175.       if ((VPointer <= VStack) || (*--VPointer != BEG_REFLECT))
  176.     BadDVIAbort("reflection commands incorrectly nested");
  177.       break;
  178.   }
  179. }
  180.  
  181.  
  182.  
  183. /*
  184.  *  As Knuth would say, ``Exit due to finiteness.''  We can become less
  185.  *  finite, but we have to know in advance!
  186.  */
  187. void
  188. BufOverflow()
  189. {
  190.   fprintf(stderr, "\n%s: Buffer size %d was inadequate\n",
  191.           ProgramName, BufSize);
  192.   fprintf(stderr, "(Use the -b flag to increase the buffer size)\n");
  193.   exit(3);
  194. }
  195.  
  196.  
  197.  
  198.  
  199. /*
  200.  *  Read a command.  Just read a byte with /ReadingCommand/ turned on
  201.  *  (and then turn it off!).  See the discussion of /VStack/ above.
  202.  */
  203. unsigned_byte
  204. ReadCommand()
  205. {
  206.   unsigned_byte result;
  207.  
  208.   ReadingCommand = TRUE;
  209.   result = ReadByte();
  210.   ReadingCommand = FALSE;
  211.   return result;
  212. }
  213.  
  214.  
  215.  
  216.  
  217. /*
  218.  *  Copy a single byte from the input DVI file to the output file and
  219.  *  return it.
  220.  */
  221. unsigned_byte
  222. CopyByte()
  223. {
  224.   unsigned result = ReadByte();
  225.  
  226.   WriteByte(result);
  227.   return result;
  228. }
  229.  
  230.  
  231.  
  232. /*
  233.  *  Read a byte from the input file /fp/.  We don't have to worry about
  234.  *  buffering or special checks, just about EOF.  The error message is
  235.  *  justified because we do input only from the TFM file of the current
  236.  *  font (except for the main input DVI file, of course).
  237.  */
  238. unsigned_byte
  239. FReadByte(fp)
  240. FILE *fp;
  241. {
  242.     int nextchar;
  243.  
  244.     nextchar = getc(fp);
  245.     if (nextchar == EOF) {
  246.       fprintf(stderr, "\n%s: unexpected EOF in TFM file for font %s\n",
  247.               ProgramName, CurFont->name);
  248.       exit(2);
  249.     }
  250.     return nextchar;
  251. }
  252.  
  253.  
  254.  
  255.  
  256. /*
  257.  *  Discard /n/ bytes from the input DVI file.
  258.  */
  259. void
  260. SkipNBytes(n)
  261. long n;
  262. {
  263.   while (n--) (void) ReadByte();
  264. }
  265.  
  266.  
  267.  
  268. /*
  269.  *  Discard /n/ bytes from the input file /fp/.
  270.  */
  271. void
  272. FSkipNBytes(fp,n)
  273. FILE *fp;
  274. long n;
  275. {
  276.   while (n--) (void) FReadByte(fp);
  277. }
  278.  
  279.  
  280.  
  281. /*
  282.  *  Copy /n/ bytes from the input DVI file to the output file.
  283.  */
  284. void
  285. CopyNBytes(n)
  286. long n;
  287. {
  288.   while (n--) WriteByte(ReadByte());
  289. }
  290.  
  291.  
  292.  
  293.  
  294. /*
  295.  *  Read an unsigned integer of length /bytes/ from the input DVI file.
  296.  */
  297. long
  298. ReadUnsigned(bytes)
  299. unsigned bytes;
  300. {
  301.   long result = 0;
  302.  
  303.   while (bytes-- != 0) {
  304.     result <<= 8;
  305.     result |= ReadByte();
  306.   }
  307.   return result;
  308. }
  309.  
  310.  
  311.  
  312. /*
  313.  *  Read an unsigned integer of length /bytes/ from the input file /fp/.
  314.  */
  315. long
  316. FReadUnsigned(fp,bytes)
  317. FILE *fp;
  318. unsigned bytes;
  319. {
  320.   long result = 0;
  321.  
  322.   while (bytes--) {
  323.     result <<= 8;
  324.     result |= FReadByte(fp);
  325.   }
  326.   return result;
  327. }
  328.  
  329.  
  330.  
  331. /*
  332.  *  Read a signed integer of length /bytes/ from the input DVI file.
  333.  *  This must be done with no assumptions about the length of long ints
  334.  *  on the machine and without using sign-extending right shifts.
  335.  */
  336. long
  337. ReadSigned(bytes)
  338. unsigned bytes;
  339. {
  340.   long result;
  341.  
  342.   result = ReadByte();
  343.   if (result >= 128) result -= 256;
  344.   while (--bytes) {
  345.     result <<= 8;
  346.     result |= ReadByte();
  347.   }
  348.   return result;
  349. }
  350.  
  351.  
  352.  
  353. /*
  354.  *  Read a signed integer of length /bytes/ from the input file /fp/.
  355.  */
  356. long
  357. FReadSigned(fp,bytes)
  358. FILE *fp;
  359. int bytes;
  360. {
  361.   long result;
  362.  
  363.   result = FReadByte(fp);
  364.   if (result >= 128) result -= 256;
  365.   while (--bytes) {
  366.     result <<= 8;
  367.     result |= FReadByte(fp);
  368.   }
  369.   return result;
  370. }
  371.  
  372.  
  373.  
  374.  
  375. /*
  376.  *  Copy a 32-bit word from the input DVI file to the output file, and
  377.  *  return it.
  378.  */
  379. long
  380. CopyWord()
  381. {
  382.   long result = ReadSigned(4);
  383.  
  384.   WriteWord(result);
  385.   return result;
  386. }
  387.  
  388.  
  389.  
  390. /*
  391.  *  Copy an unsigned integer of length /bytes/ from the input DVI file
  392.  *  to the output file, and return it.
  393.  */
  394. long
  395. CopyUnsigned(bytes)
  396. unsigned bytes;
  397. {
  398.   long result = ReadUnsigned(bytes);
  399.  
  400.   WriteNumber(result,bytes);
  401.   return result;
  402. }
  403.  
  404.  
  405.  
  406.  
  407. /*
  408.  *  Get a file position from which we can take input later.  If we're
  409.  *  currently taking input from the buffer, the result is just the buffer
  410.  *  pointer.  If not, the saved position is the place inside the buffer
  411.  *  where we're storing the input as it comes in.  Details at /ReadByte/.
  412.  */
  413. unsigned_byte *
  414. ReadFilePosition()
  415. {
  416.   if (BufPointer) return BufPointer; else return BufFirstNonchar;
  417. }
  418.  
  419.  
  420.  
  421. /*
  422.  *  Reset to take input starting from a saved file position.  Easy.
  423.  */
  424. void
  425. ResetFilePosition(position)
  426. unsigned_byte *position;
  427. {
  428.   BufPointer = position;
  429. }
  430.  
  431.  
  432.  
  433. /*
  434.  *  Arrange to see the last character of the input again.  Possible only
  435.  *  when we're reading buffered input, in which case it's simple.  In
  436.  *  fact, this routine is used only by /SetString/ while RTYPESETTING.
  437.  */
  438. void RereadLastByte() {
  439.   if (!BufPointer || (BufPointer == Buffer)) {
  440.     fprintf(stderr, "\n%s internal error: illegal attempt to backup input\n",
  441.             ProgramName);
  442.     exit(4);
  443.   }
  444.   BufPointer--;
  445. }
  446.  
  447.  
  448.  
  449.  
  450. /*
  451.  *  Write a single byte to the output DVI file.  All non-diagnostic output
  452.  *  ***MUST*** go through this routine so that the number of bytes output
  453.  *  is counted accurately.
  454.  */
  455. void
  456. WriteByte(value)
  457. unsigned value;
  458. {
  459.   putchar(value);
  460.   BytesOutput++;
  461. }
  462.  
  463.  
  464.  
  465. /*
  466.  *  Write a 32-bit word to the output file.
  467.  */
  468. void
  469. WriteWord(value)
  470. long value;
  471. {
  472.   WriteNumber(value, 4);
  473. }
  474.  
  475.  
  476.  
  477. /*
  478.  *  Write /value/ to the output file as an integer of length /bytes/.
  479.  */
  480. void
  481. WriteNumber(value,bytes)
  482. long value;
  483. unsigned bytes;
  484. {
  485.   if (bytes > 1) WriteNumber(value >> 8, bytes - 1);
  486.   WriteByte((unsigned_byte) value & 0377);
  487. }
  488.  
  489.  
  490.  
  491. /*
  492.  *  Write a string to the output DVI file.
  493.  */
  494. void
  495. WriteString(string)
  496. char *string;
  497. {
  498.   char *pchar;
  499.  
  500.   for (pchar = string; *pchar; pchar++)
  501.     WriteByte((unsigned_byte) *pchar);
  502. }
  503.  
  504.  
  505.  
  506.  
  507. /*
  508.  *  Calculate how many bytes are required to represent /number/.  Don't
  509.  *  say  /number = -(number+1)/  because of the possibility of overflow.
  510.  */
  511. unsigned
  512. SignedBytes(number)
  513. long number;
  514. {
  515.   if (number > 0) { number = -number; number -= 1; }
  516.   if (number >= -128) return 1;
  517.   else if (number >= -(128*256)) return 2;
  518.   else if (number >= -(128*256*256)) return 3;
  519.   else return 4;
  520. }
  521.